package com.bookrecomm.service.impl;

import com.bookrecomm.dao.CategoryRepository;
import com.bookrecomm.dao.HotKeywordRepository;
import com.bookrecomm.dao.MarketTrendRepository;
import com.bookrecomm.dao.RatingDistributionRepository;
import com.bookrecomm.dao.SalesRankingRepository;
import com.bookrecomm.entity.Category;
import com.bookrecomm.entity.HotKeyword;
import com.bookrecomm.entity.MarketTrend;
import com.bookrecomm.entity.RatingDistribution;
import com.bookrecomm.entity.SalesRanking;
import com.bookrecomm.service.DataAnalysisService;
import com.bookrecomm.vo.HotKeywordVO;
import com.bookrecomm.vo.MarketTrendVO;
import com.bookrecomm.vo.RatingDistributionVO;
import com.bookrecomm.vo.SalesRankingVO;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 数据分析服务实现类
 * 提供图书销量、评分、关键词和市场趋势的数据分析功能
 */
@Service
@RequiredArgsConstructor
public class DataAnalysisServiceImpl implements DataAnalysisService {
    
    private final SalesRankingRepository salesRankingRepository;
    private final RatingDistributionRepository ratingDistributionRepository;
    private final HotKeywordRepository hotKeywordRepository;
    private final MarketTrendRepository marketTrendRepository;
    private final CategoryRepository categoryRepository;
    
    /**
     * 获取销量排行数据
     * @param categoryId 分类ID，如果为null则查询所有分类
     * @param timeRange 时间范围（day, week, month, year）
     * @param limit 限制返回记录数，默认为10
     * @return 销量排行数据列表
     */
    @Override
    public List<SalesRankingVO> getSalesRanking(Long categoryId, String timeRange, Integer limit) {
        // 计算时间范围
        LocalDateTime[] dateRange = calculateDateRange(timeRange);
        LocalDateTime startDate = dateRange[0];
        LocalDateTime endDate = dateRange[1];
        
        // 查询销量排行数据
        List<SalesRanking> salesRankings = salesRankingRepository.findTopByCategory(
                categoryId,
                startDate,
                endDate,
                PageRequest.of(0, limit == null ? 10 : limit)
        );
        
        // 转换为VO对象
        return salesRankings.stream()
                .map(sr -> SalesRankingVO.builder()
                        .bookId(sr.getBook().getId())
                        .title(sr.getBook().getTitle())
                        .cover(sr.getBook().getCoverUrl())
                        .author(sr.getBook().getAuthor())
                        .sales(sr.getSales())
                        .rating(sr.getBook().getRating())
                        .categoryName(sr.getCategory() != null ? sr.getCategory().getName() : "全部")
                        .build())
                .collect(Collectors.toList());
    }
    
    /**
     * 获取评分分布数据
     * @param categoryId 分类ID，如果为null则查询所有分类
     * @param timeRange 时间范围（day, week, month, year）
     * @return 评分分布数据
     */
    @Override
    public RatingDistributionVO getRatingDistribution(Long categoryId, String timeRange) {
        // 计算时间范围
        LocalDateTime[] dateRange = calculateDateRange(timeRange);
        LocalDateTime startDate = dateRange[0];
        LocalDateTime endDate = dateRange[1];
        
        // 查询评分分布数据
        Optional<RatingDistribution> ratingDistributionOpt = ratingDistributionRepository.findLatestByCategory(
                categoryId,
                startDate,
                endDate
        );
        
        // 如果没有找到数据，返回空数据
        if (ratingDistributionOpt.isEmpty()) {
            String categoryName = "全部";
            if (categoryId != null) {
                Optional<Category> categoryOpt = categoryRepository.findById(categoryId);
                categoryName = categoryOpt.map(Category::getName).orElse("未知分类");
            }
            return RatingDistributionVO.create(categoryId, categoryName);
        }
        
        // 转换为VO对象
        RatingDistribution rd = ratingDistributionOpt.get();
        Map<String, Integer> data = new HashMap<>();
        data.put("1", rd.getRating1Count());
        data.put("2", rd.getRating2Count());
        data.put("3", rd.getRating3Count());
        data.put("4", rd.getRating4Count());
        data.put("5", rd.getRating5Count());
        
        return RatingDistributionVO.builder()
                .categoryId(categoryId)
                .categoryName(rd.getCategory() != null ? rd.getCategory().getName() : "全部")
                .data(data)
                .build();
    }
    
    /**
     * 获取热门关键词
     * @param categoryId 分类ID，如果为null则查询所有分类
     * @param timeRange 时间范围（day, week, month, year）
     * @param limit 限制返回记录数，默认为20
     * @return 热门关键词列表
     */
    @Override
    public List<HotKeywordVO> getHotKeywords(Long categoryId, String timeRange, Integer limit) {
        // 计算时间范围
        LocalDateTime[] dateRange = calculateDateRange(timeRange);
        LocalDateTime startDate = dateRange[0];
        LocalDateTime endDate = dateRange[1];
        
        // 查询热门关键词数据
        List<HotKeyword> hotKeywords = hotKeywordRepository.findTopByCategory(
                categoryId,
                timeRange,
                startDate,
                endDate,
                PageRequest.of(0, limit == null ? 20 : limit)
        );
        
        // 转换为VO对象
        return hotKeywords.stream()
                .map(hk -> HotKeywordVO.builder()
                        .name(hk.getKeyword())
                        .value(hk.getWeight())
                        .categoryId(hk.getCategory() != null ? hk.getCategory().getId() : null)
                        .categoryName(hk.getCategory() != null ? hk.getCategory().getName() : "全部")
                        .timeRange(hk.getTimeRange())
                        .build())
                .collect(Collectors.toList());
    }
    
    /**
     * 获取市场趋势数据
     * @param categoryId 分类ID，如果为null则查询所有分类
     * @param timeRange 时间范围（day, week, month, year）
     * @return 市场趋势数据列表
     */
    @Override
    public List<MarketTrendVO> getMarketTrend(Long categoryId, String timeRange) {
        // 计算时间范围
        LocalDate startDate;
        LocalDate endDate = LocalDate.now();
        
        switch (timeRange) {
            case "day":
                startDate = endDate.minusDays(1);
                break;
            case "week":
                startDate = endDate.minusWeeks(1);
                break;
            case "month":
                startDate = endDate.minusMonths(1);
                break;
            case "year":
                startDate = endDate.minusYears(1);
                break;
            default:
                startDate = endDate.minusMonths(1); // 默认一个月
        }
        
        // 查询市场趋势数据
        List<MarketTrend> marketTrends = marketTrendRepository.findByCategoryAndDateRange(
                categoryId,
                startDate,
                endDate
        );
        
        // 如果没有找到数据，生成测试数据
        if (marketTrends.isEmpty()) {
            return generateTestMarketTrendData(categoryId, startDate, endDate);
        }
        
        // 转换为VO对象
        String categoryName = "全部";
        if (categoryId != null) {
            Optional<Category> categoryOpt = categoryRepository.findById(categoryId);
            categoryName = categoryOpt.map(Category::getName).orElse("未知分类");
        } else if (!marketTrends.isEmpty() && marketTrends.get(0).getCategory() != null) {
            categoryName = marketTrends.get(0).getCategory().getName();
        }
        
        final String finalCategoryName = categoryName;
        
        return marketTrends.stream()
                .map(mt -> MarketTrendVO.from(
                        mt.getDate(),
                        mt.getSales(),
                        mt.getAvgRating(),
                        mt.getFavoriteCount(),
                        categoryId,
                        finalCategoryName
                ))
                .collect(Collectors.toList());
    }
    
    /**
     * 计算时间范围
     * @param timeRange 时间范围（day, week, month, year）
     * @return 开始时间和结束时间的数组
     */
    private LocalDateTime[] calculateDateRange(String timeRange) {
        LocalDateTime endDate = LocalDateTime.now();
        LocalDateTime startDate;
        
        switch (timeRange) {
            case "day":
                startDate = endDate.minusDays(1);
                break;
            case "week":
                startDate = endDate.minusWeeks(1);
                break;
            case "month":
                startDate = endDate.minusMonths(1);
                break;
            case "year":
                startDate = endDate.minusYears(1);
                break;
            default:
                startDate = endDate.minusMonths(1); // 默认一个月
        }
        
        return new LocalDateTime[]{startDate, endDate};
    }
    
    /**
     * 生成测试市场趋势数据
     * 当数据库中没有数据时，生成测试数据用于前端展示
     * @param categoryId 分类ID
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 测试数据列表
     */
    private List<MarketTrendVO> generateTestMarketTrendData(Long categoryId, LocalDate startDate, LocalDate endDate) {
        List<MarketTrendVO> result = new ArrayList<>();
        
        // 获取分类名称
        String categoryName = "全部";
        if (categoryId != null) {
            Optional<Category> categoryOpt = categoryRepository.findById(categoryId);
            categoryName = categoryOpt.map(Category::getName).orElse("未知分类");
        }
        
        // 计算日期之间的天数
        long daysBetween = ChronoUnit.DAYS.between(startDate, endDate) + 1;
        
        // 生成每天的数据
        for (int i = 0; i < daysBetween; i++) {
            LocalDate date = startDate.plusDays(i);
            
            // 生成随机数据
            int sales = 100 + (int) (Math.random() * 900); // 100-1000之间的随机数
            BigDecimal rating = new BigDecimal(3.0 + Math.random() * 2.0).setScale(1, java.math.RoundingMode.HALF_UP); // 3.0-5.0之间的随机数
            int favorite = 50 + (int) (Math.random() * 450); // 50-500之间的随机数
            
            // 添加到结果列表
            result.add(MarketTrendVO.from(
                    date,
                    sales,
                    rating,
                    favorite,
                    categoryId,
                    categoryName
            ));
        }
        
        return result;
    }
}
